package com.ihr360.shared.advice.handler;

import com.google.common.base.Throwables;
import com.ihr360.commons.context.session.Ihr360Session;
import com.ihr360.commons.context.session.Ihr360SessionContextHolder;
import com.ihr360.commons.entity.AuthUserInfo;
import com.ihr360.commons.exception.Ihr360Exception;
import com.ihr360.commons.exception.Ihr360SimpleResultException;
import com.ihr360.commons.lang.StringUtils;
import com.ihr360.commons.vo.ResultInfo;
import com.ihr360.shared.exceptionmail.entity.ExceptionRecord;
import com.ihr360.shared.exceptionmail.service.ExceptionMailService;
import com.ihr360.shared.message.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * 异常 handler
 *
 * @author tom
 */
@ControllerAdvice(basePackages = "com.ihr360")
public class Ihr360ExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(Ihr360ExceptionHandler.class);

    @Value("${ihr360.exception.errorlog.enabled:false}")
    private boolean enableReturnLogInfo;

    @Autowired
    private MessageService messageService;

    @Autowired
    private ExceptionMailService exceptionMailService;

    @ResponseBody
    @ExceptionHandler(Ihr360Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultInfo handleOnclickException(Ihr360Exception e) {
        ResultInfo errorInfo = new ResultInfo();
        try {
            String message = getIhr360ExceptionMessage(e);
            errorInfo.setMessage(message);
            errorInfo.setCode(ResultInfo.INFO);
        } catch (Throwable throwable) {
            logger.error(e.getMessage(), e);
        }
        return errorInfo;
    }

    @ResponseBody
    @ExceptionHandler(Ihr360SimpleResultException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResultInfo handleIhr360SimpleResultException(Ihr360SimpleResultException e) {
        ResultInfo<String> messageInfo = new ResultInfo<>();
        try {
            if (StringUtils.isNotBlank(e.getData())) {
                messageInfo.setData(e.getData());
            }
            if (enableReturnLogInfo) {
                if (e.getMessage() != null) {
                    String message = getMessage(e.getMessage(), e.getMessageKey(), e.getArgs());
                    messageInfo.setMessage(message);
                }
            } else {
                messageInfo.setMessage("服务内容错误");
            }
            messageInfo.setCode(ResultInfo.OK);
        } catch (Throwable throwable) {
            logger.error(e.getMessage(), e);
        }
        return messageInfo;
    }

    @ResponseBody
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultInfo handleDeveloperOrientedException(RuntimeException e, HttpServletRequest request) {
        ResultInfo errorInfo = new ResultInfo();
        try {
            String message = e.getMessage();
            if (enableReturnLogInfo) {
                errorInfo.setMessage(message);
            } else {
                errorInfo.setMessage("服务内容错误");
            }
            errorInfo.setCode(ResultInfo.ERROR);

            String ip = request.getHeader("x-forwarded-for");
            String url = request.getRequestURL() != null ? request.getRequestURL().toString() : "";
            if (StringUtils.isNotBlank(request.getQueryString())) {
                url += "?" + request.getQueryString();
            }
            this.sendExceptionMail(e, url, ip);
        } catch (Throwable throwable) {
            logger.error(e.getMessage(), e.getCause());
        }
        logger.error(e.getMessage(), e);
        return errorInfo;
    }

    private String getIhr360ExceptionMessage(Ihr360Exception e) {
        return getMessage(e.getMessage(), e.getMessageKey(), e.getArgs());
    }

    private String getMessage(String message, String messageKey, Object[] args) {
        if (StringUtils.isBlank(message) || StringUtils.isBlank(messageKey)) {
            return message;
        }
        Locale locale = LocaleContextHolder.getLocale();
        if (args != null && args.length > 0) {
            Map<String, Object[]> messageParamMap = new HashMap<>();
            messageParamMap.put(messageKey, args);
            Map<String, String> messageMap = messageService.messagesMap(locale.getLanguage(), messageParamMap);
            String i18nMessage = messageMap.get(messageKey);
            return messageKey.equals(i18nMessage) ? message : i18nMessage;
        } else {
            String i18nMessage = messageService.message(locale.getLanguage(), messageKey);
            return messageKey.equals(i18nMessage) ? message : i18nMessage;
        }
    }

    private void sendExceptionMail(Exception e, String url, String serverIp) {
        ExceptionRecord exceptionRecord = new ExceptionRecord();
        exceptionRecord.setType(e.getClass().getSimpleName());
        exceptionRecord.setMessage(e.getMessage());
        exceptionRecord.setStackTrace(Throwables.getStackTraceAsString(e));
        exceptionRecord.setUrl(url);
        exceptionRecord.setServerIp(serverIp);

        Ihr360Session session = Ihr360SessionContextHolder.getSession();
        if (session != null && session.getUserInfo() != null) {
            AuthUserInfo authUserInfo = session.getUserInfo();
            exceptionRecord.setCompanyId(authUserInfo.getCompanyId());
            exceptionRecord.setCompanyName(authUserInfo.getCompanyName());
            exceptionRecord.setUserId(authUserInfo.getUserId());
            exceptionRecord.setUserName(authUserInfo.getUserName());
        }
        /*webExceptionRecord.setVersion(gitVersion.getVersion());
        webExceptionRecord.setCommitId(gitVersion.getCommitId());
        webExceptionRecord.setCommitTime(gitVersion.getCommitTime());*/
        exceptionMailService.send(exceptionRecord);
    }
}
